package com.jy.adscm.utils;

import com.jy.adscm.bean.JwdEntity;
import com.jy.adscm.bean.system.JyUser;
import com.jy.adscm.exception.AdscmSystemException;
import com.jy.adscm.security.utils.Token;
import com.jy.adscm.support.SecurityConstants;
import com.jy.adscm.utils.config.PropertiesUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.configurationprocessor.json.JSONObject;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.util.ResourceUtils;
import sun.misc.BASE64Encoder;

import javax.servlet.http.HttpServletRequest;
import java.beans.PropertyDescriptor;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author yyy
 * @ClassName StringUtils
 * @Description 工具类
 * @date 2018/7/26 19:12
 */
public class AdscmBaseUtils {

    private Logger logger = LoggerFactory.getLogger(getClass());

    private AdscmBaseUtils(){}
    private static AdscmBaseUtils stringUtils;

    public static AdscmBaseUtils getInstance(){
        synchronized (AdscmBaseUtils.class){
            if (stringUtils == null){
                stringUtils = new AdscmBaseUtils();
            }
            return stringUtils;
        }
    }

    /**
     * 给原字符串加上数据库模糊匹配查询的%符号
     * @param src
     * @return
     */
    public String addLikeStr(String src){
        if (src != null && !"".equals(src.trim())){
            src = src.replaceAll(" ","");

            char[] chars = src.toCharArray();
            StringBuffer buffer = new StringBuffer();
            buffer.append("%");

            for(int i=0;i<chars.length;i++){
                buffer.append(chars[i]);
                buffer.append("%");
            }
            src = buffer.toString();
            return src;
        }else {
            return null;
        }
    }


    /**
     * 去除字符串中的空格、回车、换行符、制表符等
     * @param str
     * @return
     */
    public static String replaceSpecialStr(String str) {
        String repl = "";
        if (str!=null) {
            Pattern p = Pattern.compile("\\s*|\t|\r|\n");
            Matcher m = p.matcher(str);
            repl = m.replaceAll("");
        }
        return repl;
    }


    /**
     * 根据地址获取地址经纬度
     * @param address
     * @return
     */
    public JwdEntity getJwdByAddress(String address){
        JwdEntity jwd = null;
        try {
//            if(PropertiesUtils.tencentApiUrl == null){
//                PropertiesUtils.tencentApiUrl = "https://apis.map.qq.com/ws/geocoder/v1/";
//            }
//            if(PropertiesUtils.tencentApiKey == null){
//                PropertiesUtils.tencentApiKey = "QWMBZ-E4VC6-JMVSB-MVKIP-HKYX2-VBFGQ";
//            }

            if(address != null && !"".equals(address)){
                StringBuffer param = new StringBuffer();
                address = AdscmBaseUtils.replaceSpecialStr(address);
                String encodeAddress = URLEncoder.encode(address, "UTF-8");
                logger.info("URL编码后的地址："+encodeAddress);
                param.append("address="+encodeAddress);
                param.append("&key="+PropertiesUtils.tencentApiKey);
                String result = HttpRequest.sendGet(PropertiesUtils.tencentApiUrl, param.toString());

                logger.info("地址服务器反馈信息："+result);

                JSONObject json = new JSONObject(result);

                int status = json.getInt("status");

                if (status == 0){//347
                    //成功
                    JSONObject location = json.getJSONObject("result").getJSONObject("location");

                    jwd = new JwdEntity();
                    jwd.setAddress(address);
                    jwd.setJd(location.getDouble("lng"));
                    jwd.setWd(location.getDouble("lat"));

                }else {
                    logger.warn("获取地址【"+address+"】经纬度异常，地址服务器反馈信息："+ result);
                }


            }


        }catch (Exception e){
            logger.error("获取地址【"+address+"】经纬度异常...",e);
        }
        return jwd;
    }

    /**
     * 在指定的字符串前拼装 指定字符串
     * @param source ：指定字符串
     * @param len：拼装出来的总长度
     * @param addStr：需要拼装的指定字符串
     * @return
     */
    public String addZeroToStr(String source,int len,String addStr){

        StringBuffer buffer = new StringBuffer();
        if (source == null){
            source = "";
        }

        for (int i=0;source != null && buffer.length() < (len - source.length()); i++){
            buffer.append(addStr);
        }

        buffer.append(source);

        return buffer.toString();
    }

    /**
     * 判断一个对象是否为空，如果指定了某个属性，则即使对象不为空，这个对象的这个属性为空，则也返回 true
     * 如果没有指定field属性，则判断对象是否为空
     * @param source
     * @param field
     * @return
     */
    public boolean isNotEmpty(Object source,String field){
        if (source == null || "".equals(source)){
            return false;
        }else{
            if (field == null || "".equals(field)){
                return true;//如果传入的属性值为null，则直接返回对象是否为空
            }else {
                Class clazz = source.getClass();
                try {
                    Field field_ = clazz.getDeclaredField(field);
                    field_.setAccessible(true); // 设置属性是可以访问的(私有的也可以)

                    Object obj = field_.get(source);
                    if (obj == null || "".equals(obj)){
                        return false;
                    }else {
                        return true;
                    }

                } catch (NoSuchFieldException e) {
                    logger.error("对象Object["+source+"]没有属性["+field+"],StringUtils.isEmpty()方法返回true...",e);
                    return false;
                } catch (IllegalAccessException e) {
                    logger.error("获取对象Object["+source+"]的属性["+field+"]异常,StringUtils.isEmpty()方法返回true...",e);
                    e.printStackTrace();
                    return false;
                }
            }

        }
    }

    /**
     * 获取请求的IP
     * @param request
     * @return
     */
    public String getIPAddress(HttpServletRequest request) {
        // 获取请求主机IP地址,如果通过代理进来，则透过防火墙获取真实IP地址

        String ip = request.getHeader("X-Forwarded-For");

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("Proxy-Client-IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("WL-Proxy-Client-IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_CLIENT_IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_X_FORWARDED_FOR");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
            }
            if("0:0:0:0:0:0:0:1".equals(ip)){
                ip = "127.0.0.1";
            }
        } else if (ip.length() > 15) {
            String[] ips = ip.split(",");
            for (int index = 0; index < ips.length; index++) {
                String strIp = (String) ips[index];
                if (!("unknown".equalsIgnoreCase(strIp))) {
                    ip = strIp;
                    break;
                }
            }
        }
        return ip;
    }


    /**
     * 根据tokenID，获取Redis中的token
     * @param tokenId
     * @param tokenRedisTemplate
     * @return
     */
    public Token getTokenByTokenId(String tokenId , RedisTemplate<Object,Token> tokenRedisTemplate){
        synchronized (this){
            if (AdscmBaseUtils.getInstance().isNotEmpty(tokenId,null)){
                logger.info("根据tokenId["+tokenId+"]获取Redis中的Token信息...");

                ValueOperations<Object,Token> vo = tokenRedisTemplate.opsForValue();
                Token token = vo.get(tokenId);

                return token;

            }else {
                return null;
            }
        }
    }

    public void cleanToken(String tokenId , RedisTemplate<Object,Token> tokenRedisTemplate) throws AdscmSystemException{
        try {
            synchronized (this){
                if (AdscmBaseUtils.getInstance().isNotEmpty(tokenId,null)){
                    logger.info("清除tokenId["+tokenId+"]在Redis中的Token信息...");

                    ValueOperations<Object,Token> vo = tokenRedisTemplate.opsForValue();
                    Token token = vo.get(tokenId);
                    if (token != null){
                        JyUser user = token.getUser();

                        tokenRedisTemplate.expire(tokenId,1 , TimeUnit.SECONDS);//设置过期时间
                        tokenRedisTemplate.expire(user.getUsername(),1 , TimeUnit.MILLISECONDS);//设置过期时间
                    }

                }
            }
        }catch (Exception e){
            throw new AdscmSystemException("清除token异常 : " + e.getMessage());
        }
    }

    /**
     * 更新token的过期时间，每个用户的每次访问，都更新他的过期时间为默认的过期时间，让他在操作的时候，永远保持在线状态
     * @param tokenId
     * @param tokenRedisTemplate
     * @throws AdscmSystemException
     */
    public void updateTokenTimeOut(String tokenId , RedisTemplate<Object,Token> tokenRedisTemplate) throws AdscmSystemException{
        try {
            synchronized (this){
                if (AdscmBaseUtils.getInstance().isNotEmpty(tokenId,null)){

                    ValueOperations<Object,Token> vo = tokenRedisTemplate.opsForValue();
                    Token token = vo.get(tokenId);
                    if (token != null){
                        JyUser user = token.getUser();

                        //设置过期时间
                        tokenRedisTemplate.expire(user.getUsername(), SecurityConstants.DEFAULT_SIGN_EXPIRE_TIME, TimeUnit.MINUTES);
                        tokenRedisTemplate.expire(token.getTokenId(),SecurityConstants.DEFAULT_SIGN_EXPIRE_TIME, TimeUnit.MINUTES);
                    }

                }
            }
        }catch (Exception e){
            throw new AdscmSystemException("更新token的过期时间异常 : " + e.getMessage());
        }
    }

//    /**
//     * 保存对象到 Redis 的 List 集合中
//     * @param listKey 保存list的key
//     * @param obj 待保存的对象
//     * @param redisTemplate
//     */
//    public void saveObjToRedisList(String listKey,Object obj,RedisTemplate<String,List<Object>> redisTemplate){
//        try {
//            synchronized (this){
//                List<Object> list = redisTemplate.opsForList().leftPop(listKey);
//
//                if (list != null && list.size()>0){
//
//                }else {
//                    list = new ArrayList<>();
//                }
//                list.add(obj);
//                redisTemplate.opsForList().leftPush(listKey,list);
//            }
//
//        }catch (Exception e){
//            logger.error("保存对象到Redis 的 list  中出现异常  " , e);
//        }
//    }


    public String readImgToBase64(String filePath){

        String base64 = "";
        try {
            InputStream inputStream = null;
            byte[] data = null;
            try {
                inputStream = new FileInputStream(filePath);
                data = new byte[inputStream.available()];
                inputStream.read(data);
                inputStream.close();
            } catch (IOException e) {
                logger.error("读取文件【"+filePath+"】异常",e);
            }
            // 加密
            BASE64Encoder encoder = new BASE64Encoder();
            if (data != null){
                base64 = encoder.encode(data);
            }

        }catch (Exception e){
            logger.error("文件【"+filePath+"】转换成Base64字符串异常",e);
        }
        return base64;

    }

    /**
     * 求一个数的相反数
     * @param num
     * @return
     */
    public int getOppositeNum(Integer num){
            if (num == null){
                num = 0;
            }
            return (num * -1);
    }


    /**
     *  复制单个文件
     *  @param  oldPath  String  原文件路径  如：c:/fqf.txt
     *  @param  newPath  String  复制后路径  如：f:/fqf.txt
     *  @return  boolean
     */
    public  void  copyFile(String  oldPath,  String  newPath)  {
        try  {
//           int  bytesum  =  0;
            int  byteread  =  0;
            File  oldfile  =  new  File(oldPath);
            if  (oldfile.exists())  {  //文件存在时
                InputStream  inStream  =  new  FileInputStream(oldPath);  //读入原文件
                FileOutputStream  fs  =  new FileOutputStream(newPath);
                byte[]  buffer  =  new  byte[1444];
//               int  length;
                while  (  (byteread  =  inStream.read(buffer))  !=  -1)  {
//                   bytesum  +=  byteread;  //字节数  文件大小
//                   System.out.println(bytesum);
                    fs.write(buffer,  0,  byteread);
                }
                inStream.close();
            }
        }
        catch  (Exception  e)  {
            System.out.println("复制单个文件操作出错");
            e.printStackTrace();

        }

    }


    /**
     *  删除文件
     *  @param  filePathAndName  String  文件路径及名称  如c:/fqf.txt
     *  @return  boolean
     */
    public  void  delFile(String  filePathAndName)  {
        try  {
            String  filePath  =  filePathAndName;
            filePath  =  filePath.toString();
            java.io.File  myDelFile  =  new  java.io.File(filePath);
            myDelFile.delete();

        }
        catch  (Exception  e)  {
            System.out.println("删除文件操作出错");
            e.printStackTrace();

        }

    }

    /**
     *  移动文件到指定目录
     *  @param  oldPath  String  如：c:/fqf.txt
     *  @param  newPath  String  如：d:/fqf.txt
     */
    public  void  moveFile(String  oldPath,  String  newPath)  {
        copyFile(oldPath,  newPath);
        delFile(oldPath);

    }


    public static void main(String[] args) {
        String s = AdscmBaseUtils.replaceSpecialStr("二环路南师大    阿斐 \n 阿斯蒂芬 ");
        System.out.println(s);
    }

    /**
     * 获取这个对象的属性值
     * @param  obj
     * @return
     */
    public  String  getFieldsInfo( Object obj,Class cls)  {
        StringBuffer sb =new StringBuffer();
        try {

            Field[] declaredFields = cls.getDeclaredFields();
            for (Field field : declaredFields) {
                PropertyDescriptor pd = new PropertyDescriptor(field.getName(), cls);
                Method getMethod = pd.getReadMethod();
                Object o1 = getMethod.invoke(obj);
                String s1 = o1 == null ? "" : o1.toString();
                sb.append(s1+" ");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sb.toString();
    }

    /**
     * 同一对象有哪些值是不同的
     * @param newobj
     * @param oldobj
     * @return
     */
    public  String  compareObj( Object newobj,Object oldobj,Class cls)  {
        StringBuffer sb =new StringBuffer();
        try {
            Field[] declaredFields = cls.getDeclaredFields();
            for (Field field : declaredFields) {
                PropertyDescriptor pd = new PropertyDescriptor(field.getName(), cls);
                Method getMethod = pd.getReadMethod();
                Object o1 = getMethod.invoke(newobj);
                Object o2 = getMethod.invoke(oldobj);

                String s1 = o1 == null ? "" : o1.toString();
                String s2 = o2 == null ? "" : o2.toString();

                if (!s1.equals(s2)) {
                    sb.append(s2+" 修改为 "+s1);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sb.toString();
    }


    /**
     * 查询用户
     * @param tokenId
     * @param tokenRedisTemplate
     * @return
     */
    public JyUser getUser(String tokenId, RedisTemplate<Object,Token> tokenRedisTemplate)    {

        JyUser user = null;
        if (tokenId != null && !"".equals(tokenId) && tokenRedisTemplate != null){
            Token token = this.getTokenByTokenId(tokenId, tokenRedisTemplate);
            if (token != null){
                user = token.getUser();
            }
        }
        return user;
    }



    private int compare(String str, String target)
    {
        int d[][];              // 矩阵
        int n = str.length();
        int m = target.length();
        int i;                  // 遍历str的
        int j;                  // 遍历target的
        char ch1;               // str的
        char ch2;               // target的
        int temp;               // 记录相同字符,在某个矩阵位置值的增量,不是0就是1
        if (n == 0) { return m; }
        if (m == 0) { return n; }
        d = new int[n + 1][m + 1];
        for (i = 0; i <= n; i++)
        {                       // 初始化第一列
            d[i][0] = i;
        }

        for (j = 0; j <= m; j++)
        {                       // 初始化第一行
            d[0][j] = j;
        }

        for (i = 1; i <= n; i++)
        {                       // 遍历str
            ch1 = str.charAt(i - 1);
            // 去匹配target
            for (j = 1; j <= m; j++)
            {
                ch2 = target.charAt(j - 1);
                if (ch1 == ch2 || ch1 == ch2+32 || ch1+32 == ch2)
                {
                    temp = 0;
                } else
                {
                    temp = 1;
                }
                // 左边+1,上边+1, 左上角+temp取最小
                d[i][j] = min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + temp);
            }
        }
        return d[n][m];
    }

    private int min(int one, int two, int three)
    {
        return (one = one < two ? one : two) < three ? one : three;
    }

    /**
     * 获取两字符串的相似度
     * @param str
     * @param target
     * @return
     */
    public float getSimilarityRatio(String str, String target)
    {
        return 1 - (float) compare(str, target) / Math.max(str.length(), target.length());
    }


//    public static void main(String[] args)
//    {
////        String str = "四川省";
////        String target = "四川省";
////        System.out.println("similarityRatio=" + AdscmBaseUtils.getInstance().getSimilarityRatio(str, target));
//
//        StringBuffer names = new StringBuffer();
//        names.append("张三、李四、王二麻子、");
//        ;
//        System.out.println();
//
//    }













    /**
     * 获取上传路径
     * @return
     */
     public String  getUploadpath(){

         File classpath = null;
         try {
             classpath = new File(ResourceUtils.getURL("classpath:").getPath());
         } catch (FileNotFoundException e) {
             e.printStackTrace();
         }
         String gitPath=classpath.getParentFile().getParentFile().getParent()+File.separator+"adscm"+File.separator+"uploads"+File.separator;
        return gitPath;
     }
}
